// 互斥锁
class GHMutexLock {
  constructor() {
    this._isLocked = false;
    this._waiting = [];
  }

  lock(cb) {
    if (this._isLocked) {
      this._waiting.push(cb);
    } else {
      this._isLocked = true;
      cb.call(this);
    }
  }

  timedLock(ttl, cb) {
    if (!this._isLocked) {
      this._isLocked = true;
      return cb.call(this);
    }

    let timer, that = this;

    this._waiting.push(function () {
      clearTimeout(timer);

      if (!cb) {
        that.unlock();
        return;
      }

      cb.call(this);
      cb = null;
    });

    timer = setTimeout(function () {
      if (cb) {
        cb.call(this, new Error('Lock timed out'));
        cb = null;
      }
    }, ttl);
  }

  tryLock() {
    if (this._isLocked) {
      return false;
    }

    this._isLocked = true;
    return true;
  }

  unlock() {
    if (!this._isLocked) {
      throw new Error('Mutex is not locked');
    }

    var waiter = this._waiting.shift();

    if (waiter) {
      waiter.call(this);
    } else {
      this._isLocked = false;
    }
  }

  resetQueue() {
    this._waiting = [];
  }

  get isLocked() {
    return this._isLocked;
  }
}

export default GHMutexLock;

